/*
 * Copyright (C) 2013 Timothy Woodford.  All rights reserved.
 */
package sengine;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.glu.GLU;

/**
 * Base class for OpenGL/lwjgl-based games
 *
 * @author timothy
 */
public abstract class GLGame {

    private long lastUpdate;
    private int width=1600;
    private int height=900;
    private int view=0;
    
    public void run() throws LWJGLException {
        Display.setInitialBackground(1, 1, 1);
        glSetup(width,height, this.getClass().getSimpleName());
        lastUpdate = System.currentTimeMillis();
        runLoop();
    }

    protected final void glSetup(int width, int height, String name) throws LWJGLException {
        PixelFormat pixelFormat = new PixelFormat();

        Display.setDisplayMode(new DisplayMode(width, height));
        try {
            DisplayMode targetDisplayMode = null;
            DisplayMode[] modes = Display.getAvailableDisplayModes();
            int freq = 0;
            for (DisplayMode current : modes) {
                if ((current.getWidth() == width) && (current.getHeight() == height)) {
                    if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
                        if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
                            targetDisplayMode = current;
                            freq = targetDisplayMode.getFrequency();
                        }
                    }
                    if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel())
                            && (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
                        targetDisplayMode = current;
                        break;
                    }
                }
            }
            if (targetDisplayMode == null) {
                System.err.println("Could not find suitable display");
                System.exit(-1);
            }
            Display.setDisplayMode(targetDisplayMode);
            Display.setFullscreen(true);

        } catch (LWJGLException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        Display.setTitle(name);
        Display.create(pixelFormat);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        glMatrixMode(GL_MODELVIEW);

        glViewport(0, 0, width, height);
        glOrtho(0, width, height, 0, 1, -1);
        
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        fatalErrorCheck();
    }
    
    public int getWidth(){
        return width;
    }
    public int getHeight(){
        return height;
    }
    public int getView() {
        return view;
    }
    public void setView(int view) {
        this.view = view;
    }
    
    protected void runLoop() {
        while (!Display.isCloseRequested()) {
            // Graphics
            glClear(GL_COLOR_BUFFER_BIT);

            long nextTime = System.currentTimeMillis();
            render(nextTime - lastUpdate);
//            System.out.println("ms/frame: "+(nextTime - lastUpdate));
            lastUpdate = nextTime;

            Display.sync(60);
            Display.update();

            // Keyboard
            while (Keyboard.next()) {
                if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
                    glDestroy();
                    System.exit(0);
                } else {
                    keyEvent(Keyboard.getEventKey(), Keyboard.getEventKeyState());
                }
            }
        }
    }

    protected final void glDestroy() {
        Display.destroy();
    }

    protected abstract void render(long millis);

    protected abstract void keyEvent(int key, boolean down);

    public void fatalErrorCheck() {
        int errorValue = glGetError();

        if (errorValue != GL_NO_ERROR) {
            String errorString = GLU.gluErrorString(errorValue);
            System.err.println("ERROR : " + errorString);

            if (Display.isCreated()) {
                Display.destroy();
            }

            System.exit(-1);
        }
    }
}
